﻿using System;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace Team.AnonymousSurvey.SurveyEventReceiver
{
    public class SurveyEventReceiver : SPItemEventReceiver
    {
        #region constants

        private const string NotAllowedToRespondTwice = @"You are not allowed to respond again to this survey."; //Message for User if they want to fill the survey the second time.
        private const string EventReceiver = @"Event Receiver"; //Category for Logging
        private const string Completed = @"Completed"; //Survey Field, defines if the survey is finished.
        private const string SystemUser = @"Sharepoint\system"; //login name of System User, to replace Survey User with.
        private const string SurveyHistory = @"SurveysHistory"; //Survey History List Name
        private const string Notes = @"Notes"; //SurveyHistory field name for storing list of passed surveys.

        #endregion

        //Replace User name if Confidential survey. Create a record in the SurveyHistory List to be able to restrict user from filling the survey more then once.
        public override void ItemAdded(SPItemEventProperties properties)
        {
            RemoveUserAndUpdateHistory(properties);
        }

        //Same as added, but if there are more then 1 page - added is fired on the Next button click and Updated on the Finish button.
        public override void ItemUpdated(SPItemEventProperties properties)
        {
            RemoveUserAndUpdateHistory(properties);
        }

        //Check if the user has already filled the survey. If yes - do not allow to save. (can't check on form opening.)
        public override void ItemAdding(SPItemEventProperties properties)
        {
            try
            {
                var createdBy = properties.UserDisplayName;
                var webId = properties.Web.ID;
                var webUrl = properties.WebUrl;

                //run this block as System Account to get list, 
                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    using (var site = new SPSite(webUrl))
                    {
                        using (var web = site.OpenWeb(webId))
                        {
                            var surveyList = web.Lists[properties.ListId];
                            if (!surveyList.ShowUser) //replace User only if ShowUser is set to know. (we don't need to change it if Survey is NOT ananymous)
                            {
                                if (GetUserSurveyHistory(createdBy, surveyList.Title, webId, webUrl))
                                {
                                    properties.Status = SPEventReceiverStatus.CancelWithError;
                                    properties.ErrorMessage = NotAllowedToRespondTwice;
                                }
                            }
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory(EventReceiver, TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
            }
            
        }

        private void RemoveUserAndUpdateHistory(SPItemEventProperties properties)
        {
            try
            {
                var createdBy = properties.UserDisplayName;
                var webId = properties.Web.ID;
                var webUrl = properties.WebUrl;

                //update response to replace the user with the System one
                //run this block as System Account
                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    using (var site = new SPSite(webUrl))
                    {
                        using (var web = site.OpenWeb(webId))
                        {
                            var surveyList = web.Lists[properties.ListId];
                            if (!surveyList.ShowUser && properties.ListItem != null)
                            {
                                SPListItem item = surveyList.GetItemById(properties.ListItem.ID);
                                if (item != null && item[Completed].ToString() == "1")
                                {
                                    var user = web.EnsureUser(SystemUser);
                                    var userToSet = string.Format("{0};#{1}", user.ID, user.LoginName);

                                    item[SPBuiltInFieldId.Author] = userToSet;
                                    item[SPBuiltInFieldId.Editor] = userToSet; //we don't really need to update this field as it will be updated automatically, but just in case.
                                    
                                    DisableEventFiring(); //we don't want Evernt Receiver to start once again after this update and stuck in the loop.
                                    item.Update();
                                    EnableEventFiring();

                                    UpdateUserSurveyHistory(createdBy, surveyList.Title, webId, webUrl);
                                }
                            }
                        }
                    }
                });
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory(EventReceiver, TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
            }
        }

        private void UpdateUserSurveyHistory(string userName, string surveyName, Guid webId, string webUrl)
        {
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    using (var site = new SPSite(webUrl))
                    {
                        using (var web = site.OpenWeb(webId))
                        {
                            var surveysHistoryList = web.Lists[SurveyHistory];
                            
                            //Generate CAML query to get only records for the user
                            var queryBuilder = new StringBuilder();
                            queryBuilder.Append("<Where>");
                            queryBuilder.AppendFormat("<Eq><FieldRef Name='Title'/><Value Type='Text'>{0}</Value></Eq>", userName);
                            queryBuilder.Append("</Where>");
                            var query = new SPQuery {Query = queryBuilder.ToString()};

                            var items = surveysHistoryList.GetItems(query);
                            if (items.Count > 0)
                            {
                                //update existing record.
                                SPListItem item = items[0];
                                var currentHistory = item[Notes];
                                item[Notes] = string.Format("{0}{1} ", currentHistory, surveyName);
                                item.Update();
                            }
                            else
                            {
                                //create new record.
                                SPListItem newSurveyItem = surveysHistoryList.Items.Add();
                                newSurveyItem[SPBuiltInFieldId.Title] = userName;
                                newSurveyItem[Notes] = string.Format("{0} ", surveyName);
                                newSurveyItem.Update();
                            }
                        }
                    }
                });

            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory(EventReceiver, TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
            }
        }

        private bool GetUserSurveyHistory(string userName, string surveyName, Guid webId, string webUrl)
        {
            var isItemExist = false;
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    using (var site = new SPSite(webUrl))
                    {
                        using (var web = site.OpenWeb(webId))
                        {
                            var surveysHistoryList = web.Lists[SurveyHistory];

                            //Generate CAML query to get only records for the user
                            var queryBuilder = new StringBuilder();
                            queryBuilder.Append("<Where>");
                            queryBuilder.AppendFormat("<Eq><FieldRef Name='Title'/><Value Type='Text'>{0}</Value></Eq>", userName);
                            queryBuilder.Append("</Where>");
                            var query = new SPQuery { Query = queryBuilder.ToString() };
                           
                            var items = surveysHistoryList.GetItems(query);
                            if (items.Count > 0)
                            {
                                isItemExist = items[0][Notes].ToString().Contains(surveyName); //check if user already participated in the Survey
                            }
                        }
                    }
                });
                return isItemExist;
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory(EventReceiver, TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
                return isItemExist;
            }
        }
    }
}